home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_400
/
431_01
/
comio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-02
|
6KB
|
260 lines
/*
serial i/o stuff. does not use the 16550a FIFO.
i do not track line errors such as parity, overrun, or framing as
it would require 2 bytes / character instead of 1 and i want to
save some memory. since i do various block checks internally, it
is also redundant.
*/
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <string.h>
#include "comio.h"
#include "myalloc.h"
#include "local.h"
extern void com0_init(void);
extern void com0_shutdown(void);
extern void interrupt com0();
/*
port 0x3f8 / irq 4 / int c = #1
port 0x2f8 / irq 3 / int b = #2
*/
/*
transmit / recieve buffer
*/
int TRB, /* transmit/recieve character buffer */
IER, /* interrupt enable */
IIR, /* interrupt identification */
LCR, /* line control */
MCR, /* modem control */
LSR, /* line status */
MSR; /* modem status */
int xmitlen; /* number of bytes left to transmit */
BYTE *xmitptr; /* next byte in transmit buffer */
BYTE *rcvbuf; /* recieve buffer (queue) */
int rcv_head,
rcv_tail,
rcv_size; /* actual buffer size MUST BE one less than a power
of 2 */
LOCAL int irq; /* irq address */
LOCAL int irq_int; /* interrupt address */
LOCAL void interrupt (*oldint14)();
DWORD total_sent;
DWORD total_rcvd;
/*
i read as a footnote somewhere that the IIR bits are not always
accurate, thus the reason i check LSR before doing any work...
i loop in here to catch high speed transmission in bursts
*/
void CommIO(void)
{
do {
int stat=inportb(LSR); /* get line status */
inportb(MSR); /* ignore modem status */
/*
if byte pending in buffer, get it
*/
if (stat & 0x01) {
int byte=inportb(TRB);
total_rcvd++;
if (((rcv_head+1) & rcv_size) != rcv_tail)
rcvbuf[rcv_head++]=byte;
rcv_head &= rcv_size;
}
/*
if byte ready to be sent, send it
*/
if (xmitlen && (stat & 0x20)) {
total_sent++;
outportb(TRB, *(xmitptr++));
xmitlen--;
}
} while ((!(inportb(IIR) & 0x01)));
}
void CommIO_shutdown(void)
{
if (irq_int) {
outportb(0x21, inportb(0x21) | (1 << irq));
setvect(irq_int, *oldint14);
irq_int=0;
outportb(IER, 0);
com0_shutdown();
my_free(rcvbuf);
}
}
int MODE;
/*
com = 1, 2, 3, 4
mode = or'd options
baud = baud rate
pirq = irq # override (-1 for default), 0 = use polled
pbaseport = base port override (-1 for default)
return
0 if initialized, else fail code
*/
int CommIO_Initialize(int com,
int mode,
long baud,
int pirq,
int pbaseport)
{
int base;
MODE=mode;
xmitlen=0;
xmitptr=0;
rcv_size=2047;
rcvbuf=my_malloc(rcv_size+1);
if (!rcvbuf)
return 1;
com--;
base = (pbaseport < 0) ? *(WORD *) MK_FP(0x40, 2*com) : pbaseport;
irq = (pirq < 0) ? 0x04-(com & 0x01): pirq;
irq_int = irq ? 0x08+irq : 0;
TRB =(base);
IER =(base+1);
IIR =(base+2);
LCR =(base+3);
MCR =(base+4);
LSR =(base+5);
MSR =(base+6);
baud = 115200/baud;
if (!baud) /* must be at least 1 */
baud++;
outportb(LCR, mode | 0x80); /* set baud rate & mode */
outportb(TRB, baud & 0xff);
outportb(TRB+1, baud >> 8);
outportb(LCR, mode);
outportb(MCR, 0);
com0_init();
if (irq_int) {
oldint14=getvect(irq_int);
setvect(irq_int, com0);
outportb(0x21, inportb(0x21) & ~(1 << irq)); /* enable the interrupt */
outportb(IER, 0x03); /* enable line status change interrupt */
do {
inportb(TRB); /* clear any pending bytes */
inportb(LSR); /* clear the line status register */
inportb(MSR);
} while (!(inportb(IIR) & 0x01));
outportb(MCR, 0x0c);
} else {
outportb(IER, 0x00);
outportb(MCR, 0x00);
}
return 0;
}
void CommIO_Transmit(void *buf, int len)
{
xmitlen=0; /* clear pending xmit */
while ((inportb(LSR) & 0x20) == 0); /* wait for xmit buffer to empty */
if (len) {
xmitptr=((char *) buf)+1;
outportb(TRB, *(char *) buf); /* transmit first character */
xmitlen=len-1; /* set length to buffer - 1 */
}
}
/*
return the next byte in the queue, -1 on error
*/
int CommIO_GetByte(void)
{
if (rcv_head == rcv_tail)
return -1;
else {
int byte=rcvbuf[rcv_tail++];
rcv_tail &= rcv_size;
return byte;
}
}
/*
return TRUE if there are bytes in the queue, else FALSE
*/
int CommIO_RecievePending(void)
{
return (rcv_tail != rcv_head);
}
/*
return TRUE if we are mid-transmit, else FALSE
*/
int CommIO_TransmitPending(void)
{
return (xmitlen);
}
/*
return >= 0 == byte
< 0 == error
timeout in 1/18 sec
*/
int CommIO_WaitByte(unsigned timeout)
{
long clk=CLOCK;
while (!CommIO_RecievePending() && (labs(CLOCK-clk) < timeout));
return CommIO_GetByte();
}
/*
flush the recieve queue
*/
void CommIO_FlushBuffer(void)
{
rcv_head=rcv_tail=0;
}
void CommIO_TransmitLoop(void *buf, int len)
{
char *out=buf;
xmitlen=0; /* clear pending xmit */
outportb(LCR, MODE);
while ((inportb(LSR) & 0x20) == 0); /* wait for xmit buffer to empty */
while (len--) {
outportb(TRB, *(out++));
total_sent++;
while ((inportb(LSR) & 0x20) == 0); /* wait for xmit buffer to empty */
}
}
int CommIO_WaitByteLoop(unsigned timeout)
{
long clk=CLOCK;
while (!(inportb(LSR) & 0x01)) {
if (labs(CLOCK-clk) >= timeout) {
outportb(LCR, MODE);
return -1;
}
}
total_rcvd++;
{
int key=inportb(TRB);
return key;
}
}